package sg.edu.nus.iss.vmcs.store;

/*
 * Copyright 2003 ISS.
 * The contents contained in this document may not be reproduced in any
 * form or by any means, without the written permission of ISS, other
 * than for the purpose for which it has been supplied.
 *
 */

import java.io.*;

import sg.edu.nus.iss.vmcs.system.ProductFactory;

/**
 * This controller will control the operations on CashStore and ProductStore
 * major operations including reading from property file and creating the list of StoreItems into the respective store
 * saving current state of StoreItems back into property files
 *
 * @version 3.0 5/07/2003
 * @author Olivo Miotto, Pang Ping Li
 */

public class StoreController {

	private CashStore cStore;
	private ProductStore dStore;

	private PropertyLoader cashLoader;
	private PropertyLoader productsLoader;


	/**
	 * Constructor that creates a StoreController with cashloader and
	 * productsloader
	 * 
	 * @param cashLoader
	 *            the PropertyLoader that has loaded the CashProperty file
	 * @param productsLoader
	 *            the PropertyLoader that has loaded the ProductProperty file
	 */
	public StoreController(
		PropertyLoader cashLoader,
		PropertyLoader productsLoader) {
		this.cashLoader = cashLoader;
		this.productsLoader = productsLoader;
	}

	/**
	 * Create new instances of CashStore and ProductStore and initialise the
	 * Stores
	 * 
	 * @throws IOException
	 *             if property files is not found
	 */
	public void initialize() throws IOException {
		cStore = new CashStore();
		dStore = ProductFactory.getFactory().createProductStore();
		initializeStores();
	}


	/**
	 * Initialise the CashStore and ProductStore by calling the following two
	 * method
	 * 
	 * @throw IOException if property files is not found
	 */
	private void initializeStores() throws IOException {
		initializeCashStore();
		initializeProductStore();
	}

	/**
	 * Initialise the ProductStore calling the its property file
	 * 
	 * @throw IOException if property files is not found
	 */
	private void initializeProductStore() throws IOException {

		// get the product file from the environment property file;
		int numOfItems = productsLoader.getNumOfItems();
		dStore.setStoreSize(numOfItems);

		for (int i = 0; i < numOfItems; i++) {
            ProductStoreItem item = (ProductStoreItem) productsLoader.getItem(i);
			StoreObject brand = item.getContent();
			StoreObject existingBrand = dStore.findObject(brand.getName());
			if (existingBrand != null) {
			    item.setContent(existingBrand);
			}
			dStore.addItem(i, item);
		}
	}

	/**
	 * Initialise the CashStore calling the its property file
	 * 
	 * @throw IOException if property files is not found
	 */
	private void initializeCashStore() throws IOException {

		// get the cash file from the environment property file;
		int numOfItems = cashLoader.getNumOfItems();
		cStore.setStoreSize(numOfItems);

		for (int i = 0; i < numOfItems; i++) {
		    CashStoreItem item = (CashStoreItem) cashLoader.getItem(i);
			cStore.addItem(i, item);
		}
	}

	/**
	 * Locate a coin and increment its quantity
	 * 
	 * @param c
	 *            the coin to be incremented
	 */
	public void storeCoin(Coin c) {
		int idx = cStore.findCashStoreIndex(c);
		CashStoreItem item;
		item = (CashStoreItem) this.getStoreItem(Store.CASH, idx);
		item.increment();
	}

	/**
	 * Get the store size by their type
	 * 
	 * @param type
	 *            the type of store
	 * @return return the store size
	 */
	public int getStoreSize(int type) {
		if (type == Store.CASH)
			return cStore.getStoreSize();
		else
			return dStore.getStoreSize();
	}

	/**
	 * Get an array of the store's item by their type
	 * 
	 * @param type
	 *            the type of store
	 * @return return an array of the store's item
	 */
	public StoreItem[] getStoreItems(int type) {
		if (type == Store.CASH)
			return cStore.getItems();
		else
			return dStore.getItems();
	}

	/**
	 * Change the quantity of the store's item by their index
	 * 
	 * @param type
	 *            the type of store
	 * @param idx
	 *            the index of the item to change
	 * @param qty
	 *            the quantity to set
	 */
	public void changeStoreQty(int type, int idx, int qty) {
			System.out.println(
				"StoreController.changeStoreQty: type:"
					+ type
					+ "   qty:"
					+ qty);
			if (type == Store.CASH)
				cStore.setQuantity(idx, qty);
			else
				dStore.setQuantity(idx, qty);
	}


	/**
	 * Get the store's item by their index
	 * 
	 * @param type
	 *            the type of store
	 * @param idx
	 *            the index of the item return
	 * @return the StoreItem with the type and index passed in
	 */
	public StoreItem getStoreItem(int type, int idx) {
		if (type == Store.CASH)
			return cStore.getStoreItem(idx);
		else
			return dStore.getStoreItem(idx);
	}

	/**
	 * Set the Productstore price by the index
	 * 
	 * @param idx
	 *            the index of the item
	 * @param pr
	 *            the new price of the item
	 */
	public void setPrice(int idx, int pr)  {
		ProductStoreItem item;

		item = (ProductStoreItem) dStore.getStoreItem(idx);
		ProductBrand bd;

		bd = (ProductBrand) item.getContent();

		bd.setPrice(pr);
	}

	/**
	 * Get the total cash amount in the CashStore
	 * 
	 * @return the total cash amount in int
	 */
	public int getTotalCash()   {
		int i;
		int size;

		size = cStore.getStoreSize();
		CashStoreItem item;
		int qty;
		int val;
		int tc = 0;
		Coin c;

		for (i = 0; i < size; i++) {
			item = (CashStoreItem) cStore.getStoreItem(i);
			qty = item.getQuantity();
			c = (Coin) item.getContent();
			val = c.getValue();
			tc = tc + qty * val;
		}
		return tc;
	}

	/**
	 * Set all quantity of coin to zero and return a total
	 * 
	 * @return the total cash amount in int
	 */
	public int transferAll()  {
		int i;
		int cc = 0; // coin quauntity;
		int size = cStore.getStoreSize();

		CashStoreItem item;
		for (i = 0; i < size; i++) {
			item = (CashStoreItem) cStore.getStoreItem(i);
			cc = cc + item.getQuantity();
			item.setQuantity(0);
		}

		return cc;
	}

	/**
	 * Close down the application, call saveCashProperties() and
	 * saveProductsProperties()
	 * 
	 * @throws IOException
	 *             if property files not found
	 */
	public void closeDown() throws IOException {
		// save back cash property;
		saveCashProperties();
        saveProductsProperties();
	}

	/**
	 * Save cash Property into property file
	 * 
	 * @throws IOException
	 *             if property file not found
	 */
	private void saveCashProperties() throws IOException {
		int size = cStore.getStoreSize();
		cashLoader.setNumOfItems(size);
		for (int i = 0; i < size; i++) {
			cashLoader.setItem(i, cStore.getStoreItem(i));
		}
		cashLoader.saveProperty();
	}

	/**
	 * Save products property into property file
	 * 
	 * @throws IOException
	 *             if property file not found
	 */
	private void saveProductsProperties() throws IOException {
		int size = dStore.getStoreSize();
		productsLoader.setNumOfItems(size);
		for (int i = 0; i < size; i++) {
			productsLoader.setItem(i, dStore.getStoreItem(i));
		}
		productsLoader.saveProperty();
	}

	/**
	 * Decrease the quantity of the ProductStoreItem Simulate a dispense of a
	 * product
	 * 
	 * @param idx
	 *            the index of the ProductStoreItem to decrease
	 */
	public void dispenseProduct(int idx)  {
		ProductStoreItem item;
		item = (ProductStoreItem) getStoreItem(Store.PRODUCT, idx);
		item.decrement();
	}

	/**
	 * Get the Store by its type
	 * 
	 * @param type
	 *            the type of store
	 * @return return the store
	 */
	public Store getStore(int type) {
		if (type == Store.CASH)
			return (Store) cStore;
		else
			return (Store) dStore;
	}


	/**
	 * Decrease the quantity of the CashStoreItem Simulate a giving of change
	 * 
	 * @param idx
	 *            the index of the CashStoreItem to decrease
	 * @param numOfCoins
	 *            the amount of coins to decrease
	 */
	public void giveChange(int idx, int numOfCoins)  {
		CashStoreItem item;
		item = (CashStoreItem) getStoreItem(Store.CASH, idx);
		for (int i = 0; i < numOfCoins; i++)
			item.decrement();
	}
}
